package com.cryptoneedle.center.source.service.metadata;


import com.baomidou.dynamic.datasource.annotation.DS;
import com.bubbles.engine.data.core.repository.BaseRepository;
import com.bubbles.engine.data.core.service.BaseService;
import com.cryptoneedle.center.source.entity.metadata.SourceCatalog;
import com.cryptoneedle.center.source.entity.metadata.SourceDatabase;
import com.cryptoneedle.center.source.entity.metadata.SourceJdbc;
import com.cryptoneedle.center.source.key.metadata.SourceDatabaseKey;
import com.cryptoneedle.center.source.properties.SshProperties;
import com.cryptoneedle.center.source.repository.metadata.SourceDatabaseRepository;
import com.cryptoneedle.center.source.service.constraint.*;
import com.cryptoneedle.center.source.service.enhance.SourceEnhanceDimensionService;
import com.cryptoneedle.center.source.service.enhance.SourceEnhanceDorisAnalyzeColumnService;
import com.cryptoneedle.center.source.service.enhance.SourceEnhanceDorisAnalyzeTableService;
import com.cryptoneedle.center.source.service.enhance.SourceEnhanceIncrementService;
import com.cryptoneedle.center.source.util.JdbcUtil;
import com.cryptoneedle.center.source.util.SshManager;
import com.google.common.collect.Maps;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * <p>description: 源数据源-数据库 </p>
 *
 * @author CryptoNeedle
 * @date 2025-06-20
 */
@DS("pg")
@Slf4j
@Service
public class SourceDatabaseService extends BaseService<SourceDatabase, SourceDatabaseKey> {
    
    @Resource
    private SourceDatabaseRepository sourceDatabaseRepository;
    
    @Override
    public BaseRepository<SourceDatabase, SourceDatabaseKey> getRepository() {
        return this.sourceDatabaseRepository;
    }
    
    @Resource
    private SourceJdbcService sourceJdbcService;
    
    @Resource
    private SourceServerService sourceServerService;
    
    @Resource
    private SourceCatalogService sourceCatalogService;
    
    @Resource
    private SourceDatabaseService sourceDatabaseService;
    
    @Resource
    private SourceTableService sourceTableService;
    
    @Resource
    private SourceColumnService sourceColumnService;
    
    @Resource
    private SourceConstraintPrimaryService sourceConstraintPrimaryService;
    
    @Resource
    private SourceConstraintUniqueService sourceConstraintUniqueService;
    
    @Resource
    private SourceConstraintForeignService sourceConstraintForeignService;
    
    @Resource
    private SourceConstraintCheckService sourceConstraintCheckService;
    
    @Resource
    private SourceIndexUniqueService sourceIndexUniqueService;
    
    @Resource
    private SourceEnhanceDorisAnalyzeTableService sourceEnhanceDorisAnalyzeTableService;
    
    @Resource
    private SourceEnhanceDorisAnalyzeColumnService sourceEnhanceDorisAnalyzeColumnService;
    
    @Resource
    private SourceEnhanceIncrementService sourceEnhanceIncrementService;
    
    @Resource
    private SourceEnhanceDimensionService sourceEnhanceDimensionService;
    
    @Resource
    private SshProperties sshProperties;
    
    @Resource
    private SshManager sshManager;
    
    @Transactional
    public void addList(List<SourceDatabase> sourceDatabases) {
        sourceDatabaseService.saveAll(sourceDatabases);
    }
    
    @Transactional
    public void saveList(List<SourceDatabase> sourceDatabases) {
        sourceDatabaseService.saveAll(sourceDatabases);
    }
    
    @Transactional
    public void deleteList(List<SourceDatabase> sourceDatabases) {
        sourceDatabaseService.deleteAll(sourceDatabases);
    }
    
    @Transactional
    public void syncSource(SourceCatalog sourceCatalog) {
        sourceDatabaseService.syncSource(sourceCatalog, null);
    }
    
    @Transactional
    public void syncSource(SourceCatalog sourceCatalog, SourceDatabase sourceDatabase) {
        String sourceCatalogName = sourceCatalog.getSourceCatalogName();
        SourceJdbc sourceJdbc = sourceCatalog.getSourceJdbc();
        
        JdbcTemplate jdbcTemplate = JdbcUtil.getJdbcTemplate(sourceJdbc);
        List<SourceDatabase> sourceDatabases = jdbcTemplate.query(sourceJdbc
                                                                          .getDatabaseType()
                                                                          .getDatabase()
                                                                          .getDatabaseStatisticSql(), (resultSet, rowNum) -> new SourceDatabase()
                .setSourceCatalogName(sourceCatalogName)
                .setSourceSystemCode(sourceCatalog.getSourceSystemCode())
                .setSourceDatabaseName(resultSet.getString("sourceDatabaseName"))
                .setSourceDatabaseEnabled(false)
                .setStatistic(new SourceDatabase.Statistic()
                                      .setStatisticTableCount(resultSet.getLong("statisticTableCount"))
                                      .setStatisticViewCount(resultSet.getLong("statisticViewCount"))
                                      .setStatisticColumnCount(resultSet.getLong("statisticColumnCount"))
                                      .setStatisticConstraintCount(resultSet.getLong("statisticConstraintCount"))
                                      .setStatisticIndexCount(resultSet.getLong("statisticIndexCount"))
                                      .setStatisticDatetime(new Date()))
                .setTransform(null)
                .setDoris(null)
                .setSourceCatalog(sourceCatalog));
        
        sourceDatabaseService.compareSource(sourceCatalog, sourceDatabase, sourceDatabases);
    }
    
    @Transactional
    public void compareSource(SourceCatalog sourceCatalog, SourceDatabase sourceDatabase, List<SourceDatabase> dealList) {
        List<SourceDatabase> originList = sourceCatalog.getSourceDatabases();
        // 已存在
        Map<String, SourceDatabase> originMap = Maps.uniqueIndex(originList, SourceDatabase::getSourceDatabaseName);
        // 待处理
        Map<String, SourceDatabase> dealMap = Maps.uniqueIndex(dealList, SourceDatabase::getSourceDatabaseName);
        
        // 新增
        List<SourceDatabase> extraList = dealList.stream().filter(deal -> !originMap.containsKey(deal.getSourceDatabaseName())).peek(deal -> {
        }).toList();
        
        // 保存
        List<SourceDatabase> existsList = originList.stream().filter(origin -> dealMap.containsKey(origin.getSourceDatabaseName())).peek(origin -> {
            SourceDatabase deal = dealMap.get(origin.getSourceDatabaseName());
            origin.setStatistic(deal.getStatistic());
        }).toList();
        
        // 移除
        List<SourceDatabase> missList = originList.stream().filter(item -> !dealMap.containsKey(item.getSourceDatabaseName())).toList();
        
        sourceDatabaseService.addList(extraList);
        sourceDatabaseService.saveList(existsList);
        sourceDatabaseService.deleteList(missList);
        
        if (sourceDatabase == null) {
            log.info("[SYNC] {} -> 元数据采集 -> Database => 共计{} | 新增{} | 删除{}", sourceCatalog.getSourceCatalogName(), String.format("%5d", dealList.size()), String.format("%5d", extraList.size()), String.format("%5d", missList.size()) + (
                    !missList.isEmpty() ? " => " + missList.stream().map(SourceDatabase::getSourceDatabaseName).collect(Collectors.joining(",")) :
                    ""));
        } else {
            log.info("[SYNC] {} -> {} -> 元数据采集 -> Database           => 共计{} | 新增{} | 删除{}", sourceCatalog.getSourceCatalogName(), sourceDatabase.getSourceDatabaseName(), String.format("%5d", dealList.size()), String.format("%5d", extraList.size()), String.format("%5d", missList.size()) + (
                    !missList.isEmpty() ? " => " + missList.stream().map(SourceDatabase::getSourceDatabaseName).collect(Collectors.joining(",")) :
                    ""));
        }
    }
    
    @Transactional
    public List<SourceDatabase> listEnabled() {
        return sourceDatabaseRepository.listEnabled();
    }
    
    @Transactional
    public List<SourceDatabase> listEnabled(SourceCatalog sourceCatalog) {
        return sourceDatabaseRepository.listEnabled(sourceCatalog.getSourceCatalogName());
    }
    
}